//
// Created by WYLH2 on 2024/8/20.
//

#include "PocketCube.h"
#include <iostream>
#include <stdexcept>
#include <sstream>

PocketCube::PocketCube() {
    for (int x : {1, -1}) {
        for (int y : {1, -1}) {
            for (int z : {1, -1}) {
                corners.emplace_back(std::vector<int>{x, y, z});
            }
        }
    }

    std::string colors = "ROWYGB";
    std::vector<int> color_indexes = {1, 1, 2, 2, 0, 0};

    for (int direction = 0; direction < colors.size(); ++direction) {
        auto corners_toColor = getCorners(direction);
        for (auto corner : corners_toColor) {
            corner->color[color_indexes[direction]] = std::string(1, colors[direction]);
        }
    }
}

std::vector<PocketCubeCorner*> PocketCube::getCorners(int direction) {
    std::vector<PocketCubeCorner*> result;
    std::vector<std::pair<int, int>> statements = {
        {1, 1}, {1, -1}, {2, 1}, {2, -1}, {0, -1}, {0, 1}
    };
    auto statement = statements[direction];

    for (auto &corner : corners) {
        if (corner.getCoord()[statement.first] == statement.second) {
            result.push_back(&corner);
        }
    }
    return result;
}

PocketCubeCorner* PocketCube::getCornerByCoord(std::vector<int> coord) {
    for (auto &corner : corners) {
        if (corner.getCoord() == coord) {
            return &corner;
        }
    }
    return nullptr;
}

void PocketCube::rotate(int direction, bool clockwise, int times) {
    std::vector<int> axises = {1, 1, 2, 2, 0, 0};
    std::vector<bool> direction_reverse = {true, false, true, false, false, true};

    auto corners = getCorners(direction);

    //bool miniFlag = direction_reverse[direction] ? clockwise : !clockwise;

    for (int i = 0; i < times; ++i) {
        for (auto corner : corners) {
            corner->rotate(axises[direction], direction_reverse[direction] ? clockwise : !clockwise);
        }
    }
}

std::string PocketCube::show_front_up_right_view() {
    std::vector<std::vector<int>> coords = {
        {-1, -1, 1}, {-1, 1, 1}, {1, -1, 1}, {-1, 1, 1},
        {1, 1, 1}, {1, -1, 1}, {1, 1, 1}, {1, 1, 1},
        {-1, 1, -1}, {1, -1, -1}, {1, 1, -1}, {1, 1, -1}
    };

    std::vector<int> indexes = {2, 2, 2, 1, 2, 0, 1, 0, 1, 0, 1, 0};

    std::vector<std::string> color_list;
    for (int i = 0; i < coords.size(); ++i) {
        auto corner = getCornerByCoord(coords[i]);
        color_list.push_back(corner->getColor()[indexes[i]]);
    }

    std::ostringstream result;
    result << "      " << color_list[0] << "      \n"
           << "  " << color_list[1] << "       " << color_list[2] << "  \n"
           << color_list[3] << "     " << color_list[4] << "     " << color_list[5] << "\n"
           << "    " << color_list[6] << "   " << color_list[7] << "    \n"
           << color_list[8] << "           " << color_list[9] << "\n"
           << "    " << color_list[10] << "   " << color_list[11] << "    \n";

    return result.str();
}

void PocketCube::act_formula(const std::string &formula) {
    std::vector<char> actions = {'F', 'B', 'U', 'D', 'L', 'R'};
    int cursor = 0;
    std::vector<int> prev_config = { -1, 1, 1 };  // direction, clockwise, times

    while (cursor < formula.size()) {
        char char_ = formula[cursor];

        if (char_ == '\'') {
            prev_config[1] = -prev_config[1];  // reverse the direction
        } else if (isdigit(char_)) {
            prev_config[2] = char_ - '0';  // convert char to int
        } else {
            for(int it=0; it<6; it++) {
                if (char_ == actions[it]) {
                    if (prev_config[0] != -1) {
                        rotate(prev_config[0], prev_config[1] == 1, prev_config[2]);
                    }
                    prev_config[0] = it;
                    prev_config[1] = 1;
                    prev_config[2] = 1;
                }
            }
        }

        cursor++;
    }

    // 执行最后一个指令
    if (prev_config[0] != -1) {
        rotate(prev_config[0], prev_config[1] == 1, prev_config[2]);
    }
}
